{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OpenAI Assistant V2 - RAG 테스트\n",
    "\n",
    "- 저작자: [테디노트](https://www.youtube.com/@teddynote)\n",
    "\n",
    "**코드 재배포시 출처를 남겨 주세요**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 라이브러리 업데이트\n",
    "!pip install -qU langchain-teddynote"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**OpenAI API KEY 발급 방법**\n",
    "\n",
    "- [OpenAI 키 발급방법](https://wikidocs.net/233342)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 발급 받은 키를 입력해 주세요\n",
    "openai_api_key = \"OPENAI API KEY 입력\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`.env` 에 OpenAI API KEY 를 저장해 두었다면 밑의 코드 주석을 해제하고 실행하세요."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# from dotenv import load_dotenv\n",
    "# import os\n",
    "\n",
    "# load_dotenv()\n",
    "\n",
    "# openai_api_key = os.getenv(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 주요 링크\n",
    "\n",
    "- [OpenAI Assistant 대시보드](https://platform.openai.com/assistants)\n",
    "- [OpenAI API KEY 발급](https://platform.openai.com/api-keys)\n",
    "- [OpenAI Files 스토리지](https://platform.openai.com/storage/files)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 실습에 활용한 문서\n",
    "\n",
    "소프트웨어정책연구소(SPRi) - 2023년 12월호\n",
    "\n",
    "- 저자: 유재흥(AI정책연구실 책임연구원), 이지수(AI정책연구실 위촉연구원)\n",
    "- 링크: https://spri.kr/posts/view/23669\n",
    "- 파일명: `SPRI_AI_Brief_2023년12월호_F.pdf`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 1) 설정\n",
    "\n",
    "- `_DEFAULT_RAG_INSTRUCTIONS` 는 RAG 의 instruction 입니다. 프롬프트를 자유롭게 수정하여 테스트해 보세요.\n",
    "- `OPENAI_API_KEY` 는 발급받은 OPENAI API KEY 를 입력해 주세요.\n",
    "- `PROJECT_NAME` 은 프로젝트 이름을 입력해 주세요.\n",
    "- `model_name` 은 사용할 모델을 입력해 주세요. (예, `gpt-4.1-mini`, `gpt-4.1-nano`, ...)\n",
    "- `chunk_size` 는 청크 크기를 입력해 주세요.\n",
    "- `chunk_overlap` 는 청크 중복 크기를 입력해 주세요."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_teddynote.models import OpenAIAssistant\n",
    "\n",
    "\n",
    "# RAG 시스템 프롬프트 입력\n",
    "_DEFAULT_RAG_INSTRUCTIONS = \"\"\"You are an assistant for question-answering tasks. \n",
    "Use the following pieces of retrieved context to answer the question. \n",
    "If you don't know the answer, just say that you don't know. \n",
    "Answer in Korean.\"\"\"\n",
    "\n",
    "\n",
    "# 설정(configs)\n",
    "configs = {\n",
    "    \"OPENAI_API_KEY\": openai_api_key,  # OpenAI API 키\n",
    "    \"instructions\": _DEFAULT_RAG_INSTRUCTIONS,  # RAG 시스템 프롬프트\n",
    "    \"PROJECT_NAME\": \"PDF-RAG-TEST\",  # 프로젝트 이름(자유롭게 설정)\n",
    "    \"model_name\": \"gpt-4.1-mini\",  # 사용할 OpenAI 모델 이름(gpt-4.1-mini, gpt-4.1-nano, ...)\n",
    "    \"chunk_size\": 1000,  # 청크 크기\n",
    "    \"chunk_overlap\": 100,  # 청크 중복 크기\n",
    "}\n",
    "\n",
    "\n",
    "# 인스턴스 생성\n",
    "assistant = OpenAIAssistant(configs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 2) 파일 업로드\n",
    "\n",
    "### 파일 업로드 하지 않은 경우\n",
    "\n",
    "- RAG 할 파일을 업로드 합니다.\n",
    "- 파일 업로드는 딱 1번만 하면 됩니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "이미 파일을 업로드 하였고, file_id 가 있다면, 아래 코드는 생략합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 업로드할 파일 경로\n",
    "data = \"SPRI_AI_Brief_2023년12월호_F.pdf\"\n",
    "\n",
    "# 파일 업로드 후 file_id 는 잘 보관해 두세요. (대시보드에서 나중에 확인 가능)\n",
    "file_id = assistant.upload_file(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 3-1) Assistant, VectorStore 설정\n",
    "\n",
    "(참고) 이미 있는 assistant_id, vector_id 가 있다면, `STEP 3-2` 으로 넘어가세요.\n",
    "\n",
    "- `assistant_id`, `vector_id` 는 잘 보관해 두세요 (메모장 같은 곳에...)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 업로드한 파일의 ID 리스트 생성\n",
    "file_ids = [file_id]\n",
    "\n",
    "# 새로운 어시스턴트 생성 및 ID 받기\n",
    "assistant_id, vector_id = assistant.create_new_assistant(file_ids)\n",
    "\n",
    "# 어시스턴트 설정\n",
    "assistant.setup_assistant(assistant_id)\n",
    "\n",
    "# 벡터 스토어 설정\n",
    "assistant.setup_vectorstore(vector_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 3-2) 이미 있는 assistant_id, vector_id 가 있다면, 아래와 같이 설정합니다.\n",
    "\n",
    "만약에 이미 있는 assistant_id, vector_id 가 있다면, 아래와 같이 설정합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# assistant_id = \"asst_TdJbouMO7gU.........\"\n",
    "# vector_id = \"vs_ibSoSSErFDnS9........\"\n",
    "\n",
    "# # 어시스턴트 설정\n",
    "# assistant.setup_assistant(assistant_id)\n",
    "\n",
    "# # 벡터 스토어 설정\n",
    "# assistant.setup_vectorstore(vector_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 4) 대화\n",
    "\n",
    "- `stream()` 스트리밍 기능을 지원합니다.\n",
    "- `invoke()` 는 일반 출력입니다. 답변 생성이 끝날때까지 기다렸다가 한 번에 출력합니다."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`stream()` 스트리밍 기능을 지원합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "삼성전자가 개발한 생성형 AI의 이름은 '삼성 가우스'입니다【4:0†source】."
     ]
    }
   ],
   "source": [
    "for token in assistant.stream(\"삼성전자가 개발한 생성형 AI의 이름은?\"):\n",
    "    print(token, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "아래는 좀 더 편리하게 스트리밍 출력을 해줍니다. (단, 직접 토큰을 받아서 화면에 뿌려야 하는 경우에는 이전 코드가 더 유용합니다.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The name of the generative AI developed by Samsung Electronics is \"Samsung GAUSS\"【4:0†source】."
     ]
    }
   ],
   "source": [
    "from langchain_teddynote.messages import stream_response\n",
    "\n",
    "stream_response(assistant.stream(\"이전 답변을 영어로\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`invoke()` 는 일반 출력입니다. 답변 생성이 끝날때까지 기다렸다가 한 번에 출력합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "삼성전자가 개발한 생성형 AI의 이름은 \"삼성 가우스\"입니다【4:0†source】.\n"
     ]
    }
   ],
   "source": [
    "# 질문\n",
    "print(assistant.invoke(\"삼성전자가 개발한 생성형 AI의 이름은?\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "출처는 `SPRI_AI_Brief_2023년12월호_F.pdf` 문서의 10페이지입니다【12:0†source】.\n"
     ]
    }
   ],
   "source": [
    "# 추가 질문\n",
    "print(assistant.invoke(\"이전의 답변에 대한 출처(페이지)를 알려줘\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "대화 목록을 조회합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'content': '삼성전자가 개발한 생성형 AI의 이름은?', 'role': 'user'},\n",
       " {'content': \"삼성전자가 개발한 생성형 AI의 이름은 '삼성 가우스'입니다【4:0†source】.\",\n",
       "  'role': 'assistant'},\n",
       " {'content': '이전 답변을 영어로', 'role': 'user'},\n",
       " {'content': 'The name of the generative AI developed by Samsung Electronics is \"Samsung GAUSS\"【4:0†source】.',\n",
       "  'role': 'assistant'},\n",
       " {'content': '삼성전자가 개발한 생성형 AI의 이름은?', 'role': 'user'},\n",
       " {'content': '삼성전자가 개발한 생성형 AI의 이름은 \"삼성 가우스\"입니다【4:0†source】.',\n",
       "  'role': 'assistant'},\n",
       " {'content': '이전의 답변에 대한 출처(페이지)를 알려줘', 'role': 'user'},\n",
       " {'content': '출처는 `SPRI_AI_Brief_2023년12월호_F.pdf` 문서의 10페이지입니다【12:0†source】.',\n",
       "  'role': 'assistant'}]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 대화 목록 조회\n",
    "assistant.list_chat_history()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "새로운 주제는 새로운 대화 쓰레드(thread)를 시작해야 합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 대화 초기화\n",
    "assistant.clear_chat_history()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "새로운 주제의 대화를 시작합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "구글이 앤쓰로픽에 대한 투자 계획을 발표했습니다. 구글은 2023년 10월 27일 최대 20억 달러를 앤쓰로픽에 투자하기로 합의하였으며, 이 중 5억 달러를 우선 투자했습니다. 또한 앤쓰로픽은 구글의 클라우드 서비스를 사용하기 위해 4년간 30억 달러 규모의 계약도 체결했습니다. 구글은 이미 2023년 2월에 앤쓰로픽에 5억 5천만 달러를 투자한 바 있으며, 이번 투자로 앤쓰로픽과의 협력을 강화할 계획입니다【4:0†source】."
     ]
    }
   ],
   "source": [
    "# 질문\n",
    "stream_response(\n",
    "    assistant.stream(\"구글이 앤쓰로픽에 투자 계획을 발표했습니다. 이에 대해 알려줘\")\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "### 구글과 앤쓰로픽의 투자 계획 보고서\n",
      "\n",
      "---\n",
      "\n",
      "#### 1. 투자 발표 개요\n",
      "2023년 10월 27일, 구글은 인공지능(AI) 연구 및 개발 회사인 앤쓰로픽에 대한 대규모 투자 계획을 발표했습니다.\n",
      "\n",
      "#### 2. 투자 세부 내용\n",
      "- **총 투자 금액**: 최대 20억 달러\n",
      "  - 이 중 5억 달러는 즉시 투자 진행\n",
      "- **클라우드 서비스 계약**: 앤쓰로픽은 구글의 클라우드 서비스를 이용하기 위해 4년간 30억 달러 규모의 계약을 체결\n",
      "\n",
      "#### 3. 배경 및 맥락\n",
      "이미 2023년 2월, 구글은 앤쓰로픽에 5억 5천만 달러를 투자한 바 있습니다. 이번 추가 투자로 인해 구글과 앤쓰로픽 간의 협력은 더욱 강화될 것으로 기대됩니다.\n",
      "\n",
      "#### 4. 전략적 의미\n",
      "이번 투자 및 계약을 통해 구글은 자사의 클라우드 서비스 이용을 촉진함과 동시에, 급변하는 AI 기술 분야에서의 입지를 공고히 하고자 하는 전략적 목표를 가지고 있습니다.\n",
      "\n",
      "---\n",
      "\n",
      "#### 참고 문헌\n",
      "- Source: 구글과 앤쓰로픽의 투자 계획 발표 관련 문서【4:0†source】\n"
     ]
    }
   ],
   "source": [
    "# 추가 질문\n",
    "stream_response(assistant.stream(\"이전의 답변을 보고서 양식으로 작성해 주세요\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'content': '구글이 앤쓰로픽에 투자 계획을 발표했습니다. 이에 대해 알려줘', 'role': 'user'},\n",
       " {'content': '구글이 앤쓰로픽에 대한 투자 계획을 발표했습니다. 구글은 2023년 10월 27일 최대 20억 달러를 앤쓰로픽에 투자하기로 합의하였으며, 이 중 5억 달러를 우선 투자했습니다. 또한 앤쓰로픽은 구글의 클라우드 서비스를 사용하기 위해 4년간 30억 달러 규모의 계약도 체결했습니다. 구글은 이미 2023년 2월에 앤쓰로픽에 5억 5천만 달러를 투자한 바 있으며, 이번 투자로 앤쓰로픽과의 협력을 강화할 계획입니다【4:0†source】.',\n",
       "  'role': 'assistant'},\n",
       " {'content': '이전의 답변을 보고서 양식으로 작성해 주세요', 'role': 'user'},\n",
       " {'content': '### 구글과 앤쓰로픽의 투자 계획 보고서\\n\\n---\\n\\n#### 1. 투자 발표 개요\\n2023년 10월 27일, 구글은 인공지능(AI) 연구 및 개발 회사인 앤쓰로픽에 대한 대규모 투자 계획을 발표했습니다.\\n\\n#### 2. 투자 세부 내용\\n- **총 투자 금액**: 최대 20억 달러\\n  - 이 중 5억 달러는 즉시 투자 진행\\n- **클라우드 서비스 계약**: 앤쓰로픽은 구글의 클라우드 서비스를 이용하기 위해 4년간 30억 달러 규모의 계약을 체결\\n\\n#### 3. 배경 및 맥락\\n이미 2023년 2월, 구글은 앤쓰로픽에 5억 5천만 달러를 투자한 바 있습니다. 이번 추가 투자로 인해 구글과 앤쓰로픽 간의 협력은 더욱 강화될 것으로 기대됩니다.\\n\\n#### 4. 전략적 의미\\n이번 투자 및 계약을 통해 구글은 자사의 클라우드 서비스 이용을 촉진함과 동시에, 급변하는 AI 기술 분야에서의 입지를 공고히 하고자 하는 전략적 목표를 가지고 있습니다.\\n\\n---\\n\\n#### 참고 문헌\\n- Source: 구글과 앤쓰로픽의 투자 계획 발표 관련 문서【4:0†source】\\n',\n",
       "  'role': 'assistant'}]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 대화 목록 조회\n",
    "assistant.list_chat_history()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-lwwSZlnu-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
